tutorials-and-examples/example-notebooks/M365 Defender - APIs ep3.ipynb (206 lines of code) (raw):
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Declare the required imports\r\n",
"import json\r\n",
"import time\r\n",
"import pandas as pd\r\n",
"import numpy as np\r\n",
"\r\n",
"import matplotlib.pyplot as plt\r\n",
"import urllib.request\r\n",
"import urllib.parse\r\n",
"import datetime\r\n",
"\r\n",
"# Define the variables to access the Microsoft Threat protection API using Azure APP\r\n",
"# Replace with your Tenant ID\r\n",
"tenantId = '' \r\n",
"# Replace with your Application ID\r\n",
"appId = '' \r\n",
"# Replace with the Secret for your Application\r\n",
"appSecret = '' \r\n",
"# Replace with the input JSON file with the queries you want to run\r\n",
"query_inputfile_fullpath = \"C:\\\\temp\\\\singleQUery.json\" \r\n",
"#Define the folder to save the query results as CSV\r\n",
"query_outputfolder_fullpath = \"C:\\\\Temp\\\\output\" \r\n",
"# Define the Teams channel\r\n",
"teamsurl = \"https://microsoft.webhook.office.com/webhookb2/.....\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def app_auth():\n",
" url = \"https://login.windows.net/%s/oauth2/token\" % (tenantId) # Login OAUTH2 page\n",
" resourceAppIdUri = 'https://api.security.microsoft.com' # M365 Api\n",
"\n",
" body = {\n",
" 'resource' : resourceAppIdUri,\n",
" 'client_id' : appId,\n",
" 'client_secret' : appSecret,\n",
" 'grant_type' : 'client_credentials'\n",
" }\n",
"\n",
" data = urllib.parse.urlencode(body).encode(\"utf-8\")\n",
"\n",
" req = urllib.request.Request(url, data)\n",
" response = urllib.request.urlopen(req)\n",
" jsonResponse = json.loads(response.read())\n",
" aadToken = jsonResponse[\"access_token\"] # Access token for the next hour\n",
"\n",
" return aadToken\n",
"\n",
"# Declare a function to query the M365 Defender API\n",
"def exec_mtp_query(query):\n",
" url = \"https://api.security.microsoft.com/api/advancedhunting/run\" #M365 Advanced Hunting API\n",
" headers = { \n",
" 'Content-Type' : 'application/json',\n",
" 'Accept' : 'application/json',\n",
" 'Authorization' : \"Bearer \" + aadToken\n",
" }\n",
"\n",
" data = json.dumps({ 'Query' : query }).encode(\"utf-8\")\n",
"\n",
" req = urllib.request.Request(url, data, headers)\n",
" response = urllib.request.urlopen(req)\n",
" jsonResponse = json.loads(response.read())\n",
" schema = jsonResponse[\"Schema\"]\n",
" results = jsonResponse[\"Results\"]\n",
" \n",
" df = pd.DataFrame(results)\n",
" \n",
" return df\n",
"\n",
"# Declaring a function to calculate the elapsed time during the query\n",
"def getTimeDifferenceFromNow(TimeStart, TimeEnd):\n",
" timeDiff = TimeEnd - TimeStart\n",
" return timeDiff.total_seconds() / 60\n",
"\n",
"# This function will send data to teams\n",
"def send_message_to_teams(messagetosend):\n",
" import requests\n",
" payload = {\n",
" \"text\": messagetosend\n",
" }\n",
" headers = {\n",
" 'Content-Type': 'application/json'\n",
" }\n",
" response = requests.post(teamsurl, headers=headers, data=json.dumps(payload))\n",
" if response.text == \"1\":\n",
" print(\"Message Successfully posted in teams\")\n",
" else:\n",
" print(\"Message post in teams failed\")\n",
" return response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"TimeStart = datetime.datetime.now()\n",
"TimeEnd = datetime.datetime.now()\n",
"aadToken = app_auth()\n",
"\n",
"with open(query_inputfile_fullpath) as json_file:\n",
" data = json.load(json_file)\n",
" i = 1\n",
" for p in data:\n",
" ###\n",
" str_per = (i/len(data))*100\n",
" \n",
" # check if we need a new token\n",
" Elapsed_Minutes = getTimeDifferenceFromNow(TimeStart, TimeEnd)\n",
" if round(Elapsed_Minutes) < 45:\n",
" print('Using existing AzAD token')\n",
" else:\n",
" print('Generate a new AzAD token')\n",
" aadToken = app_auth()\n",
" TimeStart = datetime.datetime.now()\n",
"\n",
"\n",
" print('\\x1b[0;30;44m' + \"Running\",i,\"of\",len(data),\" queries, we are at the \",'%.2f' %str_per,\"% of processing rules\"+ '\\x1b[0m')\n",
"\n",
" # Set the Query name from JSON source file\n",
" query_name = p['Name']\n",
" # Making all the columns visible\n",
" pd.set_option('display.max_columns', None)\n",
"\n",
" # Expanding the output of the display to be more visible\n",
" pd.set_option('max_colwidth', 200)\n",
"\n",
" print('\\x1b[6;30;42m' + \"Running the\",query_name, \"query\" + '\\x1b[0m')\n",
"\n",
" # Define the query from JSON source file\n",
" kql_query = p['Query']\n",
" if len(kql_query) != 0:\n",
" print('\\x1b[0;30;47m' + kql_query + '\\x1b[0m')\n",
" try:\n",
" query_results = exec_mtp_query(kql_query)\n",
" except Exception as query_error:\n",
" print(query_error)\n",
" else:\n",
" if len(query_results) == 0:\n",
" # wait 4 second to don't exeeed the 15 queries per 60 seconds limit\n",
" time.sleep(4)\n",
" print('\\x1b[6;30;42m' + \"No results for the\",query_name, \"query\" + '\\x1b[0m')\n",
" else:\n",
" if len(query_results) == 10000:\n",
" print('\\x1b[6;30;42m' + \"The results for the\",query_name, \"query are exeeding the 10,000 limits\" + '\\x1b[0m')\n",
" print('\\x1b[6;30;42m' + \"Results for the\",query_name, \"query\" + '\\x1b[0m')\n",
" print('\\x1b[6;30;42m' + \"The query returns\",len(query_results), \"results\" + '\\x1b[0m')\n",
" messagetosend = 'The query: ' +query_name + ', returns ' + str(len(query_results)) + ' results'\n",
" \n",
" if i == 1:\n",
" QueryResultsSummary = pd.DataFrame([[query_name,len(query_results)]], columns = ['QueryName','QueryResults'])\n",
" else:\n",
" QueryResultsSummary_temp = pd.DataFrame([[query_name,len(query_results)]], columns = ['QueryName','QueryResults'])\n",
" QueryResultsSummary = QueryResultsSummary.append(QueryResultsSummary_temp)\n",
"\n",
" display(query_results.head())\n",
" # save to Tsv\n",
" try:\n",
" file_out = query_outputfolder_fullpath+'\\\\'+query_name+'.tsv'\n",
" except Exception as file_export_error:\n",
" print(file_export_error)\n",
" else: \n",
" query_results.to_csv(file_out, sep=\"\\t\")\n",
" i = i +1\n",
" TimeEnd = datetime.datetime.now()\n",
"\n",
"# Send message summary to Teams\n",
"messagetosend = QueryResultsSummary.to_html(index = False)\n",
"#send_message_to_teams(messagetosend)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.8.5 64-bit (conda)",
"name": "python38564bitconda621362638e45467d889ff2fbfac97eae"
},
"language_info": {
"name": "python",
"version": ""
},
"metadata": {
"interpreter": {
"hash": "ecf5722fdaf1897a315d257d89d94520bfcaa453217d5becf09b39e73618b0de"
}
},
"orig_nbformat": 2
},
"nbformat": 4,
"nbformat_minor": 2
}